package com.ruoyi.common.tenant.aspect;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.utils.JwtUtils;
import com.ruoyi.common.core.utils.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.common.tenant.cache.TenantDataSourceMappingHoulder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 租户数据源切面
 *
 * @author zhuzhoulin
 */
@Slf4j
@Aspect
@Component
public class TenantDataSourceAspect implements Ordered {


    /**
     * 不需要拦截地址
     */
    public static final String[] excludeUrl = {"/logout", "/refresh"};

    /**
     * 拦截所有controller public 方法
     */
    @Pointcut("execution(public * com.ruoyi..*.controller..*.*(..))")
    public void controllerMethodPointcut() {
    }

    /**
     * 环绕切面 根据租户切换数据源
     *
     * @param point /
     * @return Object  /
     * @throws Throwable /
     */
    @Around("controllerMethodPointcut()")
    public Object controllerAround(ProceedingJoinPoint point) throws Throwable {
        String shortName = point.getSignature().toShortString();
        String requestURI = ServletUtils.getRequest().getRequestURI();
        log.info("requestUrl:[{}]",requestURI);
        String token = SecurityUtils.getToken();
        String userid = null;
        String username = null;
        String tenantId = null;
        if (StringUtils.isNotEmpty(token)) {
            userid = JwtUtils.getUserId(token);
            username = JwtUtils.getUserName(token);
            tenantId = JwtUtils.getTenantId(token);
        }

        if (StringUtils.isEmpty(tenantId)) {
            tenantId = ServletUtils.getHeader(ServletUtils.getRequest(), SecurityConstants.TENANT_ID);
        }

        if (StringUtils.isEmpty(tenantId)) {
            // 尝试从auth获取
            tenantId = ServletUtils.getHeader(ServletUtils.getRequest(), SecurityConstants.AUTH_TENANT_ID);
        }

        if (StringUtils.isEmpty(tenantId)) {
            String currentDataSourceKey = DynamicDataSourceContextHolder.peek();
            log.warn("tenantId is null， shortName:[{}],dataSourceKey:[{}]", shortName, currentDataSourceKey);
        }
        String dataSourceKey = TenantDataSourceMappingHoulder.getDataSourceKey(tenantId);

        Object result = null;
        try {
            if (StringUtils.isNotEmpty(dataSourceKey)) {
                DynamicDataSourceContextHolder.push(dataSourceKey);
                log.info("set tenant datasource, userid:[{}],username:[{}],tenantId:[{}],dataSourceKey[{}],requestURI:[{}]",
                        userid, username, tenantId, dataSourceKey, requestURI);
            }
            result = point.proceed();
        } catch (Exception e) {
            result = e;
            throw e;
        } finally {
            if (StringUtils.isNotEmpty(dataSourceKey)) {
                log.info("clear tenant datasource, userid:[{}],username:[{}],tenantId:[{}],dataSourceKey[{}],requestURI:[{}]",
                        userid, username, tenantId, dataSourceKey, requestURI);
                DynamicDataSourceContextHolder.clear();
            }
        }
        return result;
    }


    /**
     * 确保在权限认证aop执行前执行
     */
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 1;
    }
}
